﻿using Microsoft.VisualStudio.Modeling;
using Microsoft.VisualStudio.Modeling.Diagrams;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;

namespace Project.Co_DataTransformationPrototype
{

    public static partial class Operators
    {
        public partial class Operator
        {
            private bool checkMergeOperator<T>(IList<T> elementCollection)
            {
                bool result = true;
                Debug.Assert(opStore != null);

                // TODO: Implement precondition check
                if (elementCollection.OfType<EntityAttribute>() != null)
                {
                    if (elementCollection.OfType<EntityAttribute>().GroupBy(a => a.Entity.CurrentName).Count() > 1)
                        result = false;
                    else if (elementCollection.OfType<EntityAttribute>().Where(a => a.isForeignKey == true || a.isPrimaryKey == true).Count() > 0)
                        result = false;
                }

                return result;
            }
            
            public Operator MergeOperator(IList<EntityShape> elementCollection)
            {
                checkMergeOperator(elementCollection);

                if (elementCollection != null)
                {
                    // Determine the main entity
                    UI.SelectEntityDialogBox dlgBox = new UI.SelectEntityDialogBox(elementCollection.OfType<EntityShape>().ToArray());
                    System.Windows.Forms.Label lblExplanationText = dlgBox.Controls.Find("lblEntitiesCbo", true).FirstOrDefault() as System.Windows.Forms.Label;
                    if (lblExplanationText != null)
                        lblExplanationText.Text = "Select the target entity. The remaining entities will be merged into it.";
                    System.Windows.Forms.DialogResult dlgResult = dlgBox.ShowDialog();

                    if (dlgResult == System.Windows.Forms.DialogResult.OK)
                    {
                        Entity currentEntity;
                        Entity mainEntity = dlgBox.targetEntity;

                        // Merge the remaining selected entities with the mainEntity
                        foreach (EntityShape eShape in elementCollection.OfType<EntityShape>().ToList())
                        {
                            currentEntity = (eShape.ModelElement as Entity);
                            if (currentEntity.Name != mainEntity.Name)
                            {
                                // Transaction is required if you want to update elements.
                                using (Transaction t = opStore.TransactionManager.BeginTransaction("Merging entities"))
                                {
                                    foreach (EntityAttribute attribute in currentEntity.EntityAttributes.ToList())
                                    {
                                        mainEntity.EntityAttributes.Add(attribute.Copy() as EntityAttribute);
                                        if (attribute.isPrimaryKey)
                                            attribute.isPrimaryKey = false;
                                        else if (attribute.isForeignKey)
                                            attribute.isForeignKey = false;
                                        currentEntity.EntityAttributes.Remove(attribute);
                                    }
                                    currentEntity.Delete();

                                    // TODO: should commit be here or outside the for loop?
                                    t.Context.Add(GetMergeOpTransactionKey, currentEntity);
                                    t.Commit();
                                }
                            }
                        }
                    }
                }
                return this;
            }

            public Operator MergeOperator(IList<EntityAttribute> attributeCollection)
            {
                if (checkMergeOperator(attributeCollection))
                {
                    if (attributeCollection != null)
                    {
                        // Determine the combination expression
                        UI.AttributeMergeDialogBox dlgBox = new UI.AttributeMergeDialogBox(attributeCollection.ToArray());
                        System.Windows.Forms.DialogResult dlgResult = dlgBox.ShowDialog();

                        if (dlgResult == System.Windows.Forms.DialogResult.OK)
                        {
                            Entity parentEntity = attributeCollection.Select<EntityAttribute, Entity>(attr => attr.Entity).First();
                            
                            // Transaction is required if you want to update elements.
                            using (Transaction t = opStore.TransactionManager.BeginTransaction("Merging attributes"))
                            {
                                EntityAttribute newAttribute = new EntityAttribute(opStore.DefaultPartition);
                                newAttribute.isForeignKey = false;
                                newAttribute.isPrimaryKey = false;
                                newAttribute.Name = dlgBox.strNewAttributeName;
                                newAttribute.Type = dlgBox.newAttributeType;

                                parentEntity.EntityAttributes.Add(newAttribute);
                                foreach (EntityAttribute attribute in attributeCollection)
                                    attribute.Delete();

                                t.Context.Add(GetMergeOpAttributeTransactionKey, dlgBox.strCombinationExpression);
                                t.Commit();
                            }
                        }
                    }
                }
                else
                {
                    System.Windows.Forms.MessageBox.Show("The selected attributes were not from the same entity, therefore this operator will be skipped.", "Merge Operator Validation", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning);
                }

                return this;
            }
        }
    }

}